# File Name： routrpy
# Description :
# Author : ‘Xuegen Wang’
# create_date： 2025/2/28
# Change Activity: 修改路网更新逻辑
import sumolib
import xml.etree.ElementTree as ET
from datetime import datetime
import random


def get_edge_from_rouxml(ROUTE_FILE, vehicle_id):   # set_vehicle_to_rest_edge()中使用，后期可删除
    rou_tree = ET.parse(ROUTE_FILE)
    root = rou_tree.getroot()
    for vehicle in root.findall('vehicle'):
        if vehicle.get('id') == vehicle_id:
            route = vehicle.find('route')
            edge = route.get('edges')
            return edge


def extract_route_edges_from_file(ROUTE_FILE, unique=True):
    route_edges_list = []

    # 解析XML文件
    tree = ET.parse(ROUTE_FILE)
    root = tree.getroot()

    # 遍历所有的vehicle元素，提取route edges
    for vehicle in root.findall('vehicle'):
        route = vehicle.find('route')
        if route is not None:
            edges = route.get('edges')
            if unique:
                if edges not in route_edges_list:
                    route_edges_list.append(edges)
            else:
                route_edges_list.append(edges)

    return route_edges_list


def get_all_car_start_coordinates(NET_FILE, edge_type):
    tree = ET.parse(NET_FILE)
    root = tree.getroot()
    coordinates_list = []
    car_star_list = []
    converter = NetworkConverter(NET_FILE)
    for edge in root.findall("edge"):
        if edge.get("type") == edge_type:
            for lane in edge.findall("lane"):
                shape = lane.get("shape")
                coords = [tuple(map(float, coord.split(','))) for coord in shape.split(' ')]
                x_coords = [coord[0] for coord in coords]
                y_coords = [coord[1] for coord in coords]
                if abs(y_coords[0] - y_coords[1]) > 30:
                    mid_x = sum(x_coords) / len(x_coords)
                    min_y = min(y_coords)
                    new_y1 = min_y + 5
                    new_y2 = new_y1 + 19
                    coordinates_list.append((mid_x, new_y1))
                    coordinates_list.append((mid_x, new_y2))
                else:
                    mid_x = sum(x_coords) / len(x_coords)
                    avg_y = sum(y_coords) / len(y_coords)
                    coordinates_list.append((mid_x, avg_y))

    for location in coordinates_list:
        x, y = location
        edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
        if edge_id is not None and lane_pos is not None and edge_id != '':
            car_star_list.append((x, y))
    return car_star_list


##终点坐标取靠近交叉点,留出一个车道用于左转，间隔5米取一个停车点，考虑车长；垂直大道向上道路靠右的坐标和垂直大道向下道路靠左的坐标。
def get_all_rest_stop_coordinates(NET_FILE, edge_types, TRUCK_STOP_TIME):
    tree = ET.parse(NET_FILE)
    root = tree.getroot()
    coordinates_list = []
    for edge in root.findall("edge"):
        if edge.get("type") in edge_types:
            for lane in edge.findall("lane"):
                lane_index = int(lane.get("index"))
                if lane_index in [0]:  # 停车1车道
                    shape = lane.get("shape")
                    coords = [tuple(map(float, coord.split(','))) for coord in shape.split(' ')]
                    x_coords = [coord[0] for coord in coords]
                    y_coords = [coord[1] for coord in coords]
                    mid_x = sum(x_coords) / len(x_coords)
                    min_y = min(y_coords) + 2

                    coordinates = []
                    current_y = min_y
                    while current_y <= max(y_coords):
                        coordinates.append((mid_x, current_y))
                        current_y += 19

                    for coord in coordinates:
                        coordinates_list.append({
                            "coord": list(coord),
                            "type": "rest",
                            "lane": lane.get("id"),
                            "worktime": TRUCK_STOP_TIME,
                            "priority": 2
                        })
    return coordinates_list


def get_all_f_area_rest_stop_coordinates(NET_FILE, edge_types, TRUCK_STOP_TIME):
    tree = ET.parse(NET_FILE)
    root = tree.getroot()
    coordinates_list = []
    for edge in root.findall("edge"):
        if edge.get("type") in edge_types:
            for lane in edge.findall("lane"):
                lane_index = int(lane.get("index"))
                if lane_index in [0,2]:
                    shape = lane.get("shape")
                    coords = [tuple(map(float, coord.split(','))) for coord in shape.split(' ')]
                    x_coords = [coord[0] for coord in coords]
                    y_coords = [coord[1] for coord in coords]
                    min_x = min(x_coords) + 9  # x 坐标的最小值作为起点
                    mid_y = sum(y_coords) / len(y_coords)  # y 坐标取平均值保持不变

                    coordinates = []
                    current_x = min_x
                    while current_x < max(x_coords)-18:
                        coordinates.append((current_x, mid_y))
                        current_x += 19

                    for coord in coordinates:
                        coordinates_list.append({
                            "coord": list(coord),
                            "type": "rest",
                            "lane": lane.get("id"),
                            "worktime": TRUCK_STOP_TIME,
                            "priority": 1
                        })
    return coordinates_list


def get_Buffer_area_rest_stop_coordinates(NET_FILE, edge_types, TRUCK_STOP_TIME):
    tree = ET.parse(NET_FILE)
    root = tree.getroot()
    coordinates_list = []

    for edge in root.findall("edge"):
        if edge.get("type") in edge_types:
            for lane in edge.findall("lane"):
                lane_index = int(lane.get("index"))
                if lane_index in [0]:  # 检查车道索引
                    shape = lane.get("shape")
                    coords = [tuple(map(float, coord.split(','))) for coord in shape.split(' ')]
                    x_coords = [coord[0] for coord in coords]
                    y_coords = [coord[1] for coord in coords]

                    # 计算 lane 的长度（y方向的最大值和最小值之差）
                    lane_length = max(x_coords) - min(x_coords)

                    # 只保留长度大于等于9的lane
                    if lane_length >= 9:
                        # 只取一个点，使用x的中点和y的中点
                        mid_x = sum(x_coords) / len(x_coords)
                        mid_y = sum(y_coords) / len(y_coords)

                        # 添加单个坐标点
                        coordinates_list.append({
                            "coord": [mid_x, mid_y],
                            "type": "rest",
                            "lane": lane.get("id"),
                            "worktime": TRUCK_STOP_TIME,
                            "priority": 0
                        })
    return coordinates_list


def get_from_to(edge):
    if edge.startswith('-'):
        edge = edge[1:]
        from_node, to_node = edge.split('T')
        return to_node, from_node  # 反向
    else:
        from_node, to_node = edge.split('T')
        return from_node, to_node  # 正向

def find_previous_and_next_edges(route_edges, current_edge):
    if not current_edge.startswith(':'):
        raise ValueError("current_edge 必须以 ':' 开头")
    road_id = current_edge[1:].split('_')[0]

    previous_edge = None
    next_edge = None

    for i, edge in enumerate(route_edges):
        from_node, to_node = get_from_to(edge)
        if to_node == road_id:
            previous_edge = edge
            for j in range(i + 1, len(route_edges)):
                next_from_node, _ = get_from_to(route_edges[j])
                if next_from_node == road_id:
                    next_edge = route_edges[j]
                    return previous_edge, next_edge
            break

    if previous_edge is None or next_edge is None:
        return None, None
    return previous_edge, next_edge


def get_lane_length(net_file, edge_id):
    """
    从 SUMO 的 .net.xml 文件中提取指定 Edge 下第一个 Lane 的长度。
    参数:
    net_file (str): .net.xml 文件的路径。
    edge_id (str): 要查询的 Edge 的 ID。
    返回:
    float: 该 Edge 下第一个 Lane 的长度。
    异常:
    ValueError: 如果找不到 Edge、Lane 或 length 属性，则抛出错误。
    """
    tree = ET.parse(net_file)
    root = tree.getroot()

    edge = root.find(f".//edge[@id='{edge_id}']")
    if edge is None:
        raise ValueError(f"未找到 ID 为 '{edge_id}' 的 Edge。")

    lane = edge.find("lane")
    if lane is None:
        raise ValueError(f"Edge '{edge_id}' 下未找到任何 Lane。")

    length_str = lane.get("length")
    if length_str is None:
        raise ValueError(f"Edge '{edge_id}' 的 Lane 没有 'length' 属性。")
    try:
        length = float(length_str)
    except ValueError:
        raise ValueError(f"Edge '{edge_id}' 的 Lane 的长度值 '{length_str}' 无效。")

    return length


import xml.etree.ElementTree as ET


def get_all_lane_lengths(net_file):
    """
    从 SUMO 的 .net.xml 文件中提取所有 Edge 的第一个 Lane 的长度，并存储到字典中。
    参数:
    net_file (str): .net.xml 文件的路径。
    返回:
    dict: 键为 edge_id (str)，值为第一个 Lane 的长度 (float)。
    """
    # 解析 XML 文件
    tree = ET.parse(net_file)
    root = tree.getroot()

    # 初始化字典，用于存储 edge_id 和 length
    lane_lengths = {}

    # 遍历所有 edge 元素
    for edge in root.findall(".//edge"):
        # 获取 edge 的 id
        edge_id = edge.get("id")
        if edge_id is None:
            continue  # 跳过没有 id 的 edge

        # 获取第一个 lane
        lane = edge.find("lane")
        if lane is None:
            continue  # 跳过没有 lane 的 edge

        # 获取 length 属性
        length_str = lane.get("length")
        if length_str is None:
            continue  # 跳过没有 length 属性的 lane

        # 尝试将 length 转换为浮点数
        try:
            length = float(length_str)
            lane_lengths[edge_id] = length
        except ValueError:
            continue  # 跳过 length 无法转换为 float 的情况

    return lane_lengths


import hashlib
import os
import json

class VesselEncoder:
    def __init__(self, mapping_file='vessel_name_mapping.json', reset=False):
        """
        初始化 VesselEncoder 类。
        :param mapping_file: 存储船舶名称和短代码映射的 JSON 文件路径
        :param reset: 是否重置映射表（清空现有映射），默认为 False
        """
        self.mapping_file = mapping_file
        self.name_to_code = {}  # 船舶名称到短代码的映射
        self.code_to_name = {}  # 短代码到船舶名称的映射
        if reset and os.path.exists(self.mapping_file):
            os.remove(self.mapping_file)  # 如果 reset=True，删除现有文件
        if not reset:  # 如果不重置，则加载现有映射
            self.load_mapping()

    def load_mapping(self):
        """
        从 JSON 文件加载映射表。如果文件不存在或加载失败，初始化为空。
        """
        if os.path.exists(self.mapping_file):
            try:
                with open(self.mapping_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    self.name_to_code = data.get('name_to_code', {})
                    self.code_to_name = data.get('code_to_name', {})
            except Exception as e:
                print(f"Error loading mapping file: {e}")
                self.name_to_code = {}
                self.code_to_name = {}
        else:
            self.name_to_code = {}
            self.code_to_name = {}

    def save_mapping(self):
        """
        将映射表保存到 JSON 文件。
        """
        data = {
            'name_to_code': self.name_to_code,
            'code_to_name': self.code_to_name
        }
        try:
            with open(self.mapping_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"Error saving mapping file: {e}")

    def encode_vessel_name(self, vessel_name):
        """
        将船舶名称编码为短代码。
        :param vessel_name: 原始船舶名称，例如 "中外运长江003"
        :return: 短代码，例如 "5b7f9c"
        """
        if not vessel_name:  # 处理空输入
            return ""
        if vessel_name in self.name_to_code:  # 如果已编码，直接返回
            return self.name_to_code[vessel_name]

        # 生成 MD5 哈希并取前 6 位
        hash_obj = hashlib.md5(vessel_name.encode('utf-8'))
        base_code = hash_obj.hexdigest()[:6]
        short_code = base_code
        counter = 0

        # 确保短代码唯一
        while short_code in self.code_to_name:
            short_code = f"{base_code}{counter}"
            counter += 1

        # 更新映射表并保存
        self.name_to_code[vessel_name] = short_code
        self.code_to_name[short_code] = vessel_name
        self.save_mapping()
        return short_code


def initialize_rouxml(BASE_NET_FILE, task_data, truck_start_list, BATCH_SIZE, INTERVAL):
    '''
    :param BASE_NET_FILE:  每批车辆数
    :param task_data: 集卡初始
    :param truck_start_list:
    :return:
    '''
    net = sumolib.net.readNet(BASE_NET_FILE)
    rou_list = []
    radis = 20
    i = 0
    for truck_id, task_info in task_data.items():
        task_id = task_info.get("task_id")
        random_Truck_start_list = truck_start_list[i]
        i += 1
        x, y = random_Truck_start_list[0], random_Truck_start_list[1]
        edge = net.getNeighboringEdges(x, y, radis)
        if edge:
            closest_edge, distance_to_edge = sorted(edge, key=lambda e: e[1])[0]
            lane = closest_edge.getLanes()[0]
            lane_pos_temp = lane.getClosestLanePosAndDist((x, y))[0]
            lane_pos = round(lane_pos_temp, 2)
            edge_id = closest_edge.getID()
            lane_id = lane.getID()
            truck_item = {
                "truck_id": truck_id,
                "task_id": task_id,
                "departlane": lane_id,
                "departpos": lane_pos,
                "route_edges": edge_id
            }
            rou_list.append(truck_item)
    init_time = datetime.now().strftime("%Y%m%d")
    route_filename = f'{init_time}.rou.xml'
    routes_str = """<routes>
        <vType id="myType" vClass="truck" accel="5" decel="9" sigma="0.0" length="19" maxSpeed="50" callFollowMode="IDMM" actionStepLength="1" tau="1" laneChangeModel="SL2015"/>\n"""
    j = 0.000  # 初始化时间变量
    for index, truck_item in enumerate(rou_list):
        truck_id = truck_item["truck_id"]
        departlane = truck_item["departlane"]
        departpos = truck_item["departpos"]
        route_edges = truck_item["route_edges"]

        depart_time = round(j, 3)
        color = "1,0,0"
        departspeed = "1"
        truck_xml = f'    <vehicle id="{truck_id}" type="myType" depart="{depart_time}" departlane="{departlane}" departPos="{departpos}" arrivallane="0" arrivalPos="5" color="{color}" departspeed="{departspeed}">\n'
        truck_xml += f'        <route edges="{route_edges}"/>\n'
        truck_xml += '    </vehicle>\n'
        routes_str += truck_xml
        # 每50辆车后，增加5秒的出发时间间隔
        # if (index + 1) % BATCH_SIZE == 0:
        #     j += INTERVAL
        # else:
        # j += 0.001  # 保持车辆之间的最小时间间隔

    routes_str += '</routes>'
    with open(route_filename, "w") as routes:
        routes.write(routes_str)
    return route_filename


def parse_netxml(netfilename):
    """
    获取路网中对应内部道路的from的edge。
    """
    tree = ET.parse(netfilename)
    root = tree.getroot()
    via_from = {}
    via_to = {}
    for connection in root.findall('connection'):
        via = connection.get('via')
        from_edge = connection.get('from')
        to_edge = connection.get('to')
        if via and from_edge:
            via_from[via] = from_edge
        if via and to_edge:
            via_to[via] = to_edge
    return via_from, via_to

class NetworkConverter:
    def __init__(self, base_net_file):
        self.net = sumolib.net.readNet(base_net_file)
    def convert_coordinates_to_edge(self, x, y, radius=20):
        """
        将给定的坐标 (x, y) 转换为网络中的 edge_id 和 lane_pos。

        :param x: x 坐标
        :param y: y 坐标
        :param radius: 搜索半径，默认为 20
        :return: tuple (edge_id, lane_pos)，如果转换失败返回 None
        """
        edges = self.net.getNeighboringEdges(x, y, radius)
        if edges:
            closest_edge, distance_to_edge = sorted(edges, key=lambda e: e[1])[0]
            lane = closest_edge.getLanes()[0]
            lane_pos_temp = lane.getClosestLanePosAndDist((x, y))[0]
            lane_pos = round(lane_pos_temp, 2)
            edge_id = closest_edge.getID()
            return edge_id, lane_pos
        return None, None  # 如果没有找到合适的边，返回 None


def update_rouxml_with_netxml(truck_info, netfilename, VESSEL2LANE_BEFORE_UPDATE, VESSEL2LANE, TRUCK_START_LIST, configs):
    """
    使用字符串替换的方式生成包含当前仿真中所有卡车信息的 .rou.xml 文件
    :param truck_info: 卡车信息字典，格式为 {truck_id: {depart_lane, depart_pos, depart_speed, route_edges}}
    :param netfilename: .net.xml 文件名
    :return: 生成的路由文件名
    """
    converter = NetworkConverter(configs.BASE_NET_FILE)
    edge_ids_berofe_update = [
        vessel[key]['edge_id']
        for vessel in VESSEL2LANE_BEFORE_UPDATE.values()
        for key in ['s1_1Ts1_2', 's2_1Ts2_2']
        if key in vessel and 'edge_id' in vessel[key]
    ]

    edge_ids_after_update = [
        vessel[key]['edge_id']
        for vessel in VESSEL2LANE.values()
        for key in ['s1_1Ts1_2', 's2_1Ts2_2']
        if key in vessel and 'edge_id' in vessel[key]
    ]

    edge_ids_berofe_update = set(edge_ids_berofe_update)
    edge_ids_after_update = set(edge_ids_after_update)
    edge_delete = edge_ids_berofe_update - edge_ids_after_update

    # 解析 .net.xml 文件，获取 via 到 from 的映射
    via_from, via_to = parse_netxml(netfilename)

    data1 = datetime.now().strftime("%Y%m%d")
    route_filename = f"{data1}_update.rou.xml"
    # init_time = datetime.now().strftime("%Y%m%d")
    # route_filename = f'{init_time}.rou.xml'
    # 初始化 XML 内容
    routes_str = """<routes>
    <vType id="myType" vClass="truck" accel="5" decel="9" sigma="0.0" length="19" maxSpeed="50" callFollowMode="IDMM" actionStepLength="1" tau="1" laneChangeModel="SL2015"/>\n"""

    # 遍历每辆卡车，生成 XML 片段
    i = 0.0000
    for truck_id, info in truck_info.items():

        depart_lane = info["depart_lane"]
        depart_pos = info["depart_pos"]
        depart_speed = info["depart_speed"]
        route_edges = info["route_edges"]
        vehicle_route_edges = info["vehicle_route_edges"]
        depart_time = round(i, 3)  # 设置 depart 时间，避免冲突。
        color = "1,0,0"  # 默认颜色
        departspeed = str(depart_speed)  # 车辆速度

        depart_lane_index = depart_lane.rsplit("_", 1)[-1]
        if depart_lane_index is None or depart_lane_index == "":
            depart_lane_index = 0

        if depart_lane is None or depart_pos is None or depart_lane == "":
            random_truck_start_list = random.choice(TRUCK_START_LIST)
            x, y = random_truck_start_list
            edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
            if edge_id is None or lane_pos is None or edge_id == "":
                random_truck_start_list = random.choice(TRUCK_START_LIST)
                x, y = random_truck_start_list
                edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)

                depart_pos = lane_pos
                route_edges = edge_id
                depart_lane_index = 0

        elif depart_lane is not None and depart_pos is not None and depart_lane != "":
            if ":" in depart_lane:
                if depart_lane in via_from and "s1" not in depart_lane and "s2" not in depart_lane:
                    depart_edge = via_from[depart_lane]
                    if "r" in depart_lane:
                        depart_pos = 12
                    elif "rest" in depart_lane:
                        depart_pos = 2
                    route_edges = depart_edge
                elif depart_lane in via_to and "s2" in depart_lane:
                    depart_edge = via_to[depart_lane]
                    if depart_edge in edge_delete:
                        random_truck_start_list = random.choice(TRUCK_START_LIST)
                        x, y = random_truck_start_list
                        edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
                        depart_pos = lane_pos
                        route_edges = edge_id

                elif "s1" in depart_lane and (depart_lane in via_to or depart_lane in via_from):
                    random_truck_start_list = random.choice(TRUCK_START_LIST)
                    x, y = random_truck_start_list
                    edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)
                    depart_pos = lane_pos
                    route_edges = edge_id

                elif "s2" in depart_lane and depart_lane in via_to:
                    depart_edge = via_to[depart_lane]
                    depart_pos = 5
                    route_edges = depart_edge
                else:
                    depart_lane = depart_lane[:-2]
                    previous_edge, next_edge = find_previous_and_next_edges(vehicle_route_edges, depart_lane)
                    route_edges = previous_edge

        #判断是否为空的情况。
        if route_edges is None or depart_pos is None or route_edges == "" or ":" in route_edges:
            random_truck_start_list = random.choice(TRUCK_START_LIST)
            x, y = random_truck_start_list
            edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)

            if edge_id is None or lane_pos is None or edge_id == "":
                random_truck_start_list = random.choice(TRUCK_START_LIST)
                x, y = random_truck_start_list
                edge_id, lane_pos = converter.convert_coordinates_to_edge(x, y, radius=20)

            if edge_id is None or lane_pos is None or edge_id == "":
                route_edges = "-r10-10Tr11-10"
                depart_pos = 1
                depart_lane_index = 0
            else:
                route_edges = edge_id
                depart_pos = lane_pos

        # 生成每辆卡车的 XML 片段
        truck_xml = f'    <vehicle id="{truck_id}" type="myType" depart="{depart_time}" departLane="0" departPos="{depart_pos}" arrivalLane="0" arrivalPos="5" color="{color}" departSpeed="random">\n'
        truck_xml += f'        <route edges="{route_edges}"/>\n'
        truck_xml += '    </vehicle>\n'
        routes_str += truck_xml

    # 结束 XML 内容
    routes_str += '</routes>'
    with open(route_filename, "w", encoding="utf-8") as f:
        f.write(routes_str)
    return route_filename


###通过路由文件来设定上一次仿真的路径和停车点。但是在仿真重启的时候ROUTE_NETFILE不能从中获取集卡车初始位置。暂时考虑不使用。
def update_truck_rouxml_with_netxml(truck_info):
    """
    使用字符串替换的方式生成包含当前仿真中所有卡车信息的 .rou.xml 文件
    :param truck_info: 卡车信息字典，格式为 {truck_id: {depart_lane, depart_pos, depart_speed, route_edges}}
    :param netfilename: .net.xml 文件名
    :return: 生成的路由文件名
    """
    data1 = datetime.now().strftime("%Y%m%d")
    route_filename = f"{data1}_update.rou.xml"
    # 初始化 XML 内容
    routes_str = """<routes>
    <vType id="myType" vClass="truck" accel="5" decel="9" sigma="0.0" length="19" maxSpeed="50" callFollowMode="IDMM" actionStepLength="1" tau="1" laneChangeModel="SL2015"/>\n"""

    # 遍历每辆卡车，生成 XML 片段
    i = 0.0000
    for truck_id, info in truck_info.items():

        depart_lane = info["depart_lane"]
        depart_pos = info["depart_pos"]
        depart_speed = info["depart_speed"]
        route_edges = info["vehicle_route_edges"]
        truck_stops = info["truck_stops"]

        depart_time = round(i, 3)  # 设置 depart 时间，避免冲突。
        color = "1,0,0"  # 默认颜色
        departspeed = str(depart_speed)  # 车辆速度

        depart_lane_index = depart_lane.rsplit("_", 1)[-1]
        current_edge = depart_lane.split("_")[0]
        route_edges_list = route_edges.split(" ")
        if ":" in current_edge:
            prev_edge, next_edge = find_previous_and_next_edges(route_edges, current_edge)
            current_edge = prev_edge
            depart_pos = 1

            try:
                current_index = route_edges_list.index(current_edge)
            except ValueError:
                continue

            remaining_route_after_simulation = " ".join(route_edges_list[current_index:])
            truck_xml = (
                f'    <vehicle id="{truck_id}" type="myType" depart="{depart_time}" '
                f'departLane="{depart_lane}" departPos="{depart_pos}" '
                f'arrivalLane="0" arrivalPos="5" color="{color}" departSpeed="{departspeed}">\n'
            )
            truck_xml += f'        <route edges="{remaining_route_after_simulation}"/>\n'

            for stop in truck_stops:
                lane_id = stop.lane  # 停车点的车道，例如 "-r10-10Tr11-10_0"
                edge_id = lane_id.rsplit("_", 1)[0]  # 停车点的路段，例如 "-r10-10Tr11-10"

                # 找到停车点路段在路径中的索引
                try:
                    stop_index = route_edges_list.index(edge_id)
                except ValueError:
                    continue

                # 如果停车点在当前路段或之后，添加到 XML
                if stop_index >= current_index:
                    stop_xml = (
                        f'        <stop lane="{lane_id}" endPos="{stop.startPos}" '
                        f'duration="{stop.duration}"/>\n'
                    )
                    truck_xml += stop_xml

            truck_xml += '    </vehicle>\n'
            routes_str += truck_xml
        elif ":" not in current_edge:
            try:
                current_index = route_edges_list.index(current_edge)
            except ValueError:
                continue

            remaining_route_after_simulation = " ".join(route_edges_list[current_index:])
            truck_xml = (
                f'    <vehicle id="{truck_id}" type="myType" depart="{depart_time}" '
                f'departLane="{depart_lane_index}" departPos="{depart_pos}" '
                f'arrivalLane="0" arrivalPos="5" color="{color}" departSpeed="{departspeed}">\n'
            )
            truck_xml += f'        <route edges="{remaining_route_after_simulation}"/>\n'

            for stop in truck_stops:
                lane_id = stop.lane  # 停车点的车道，例如 "-r10-10Tr11-10_0"
                edge_id = lane_id.rsplit("_", 1)[0]  # 停车点的路段，例如 "-r10-10Tr11-10"

                # 找到停车点路段在路径中的索引
                try:
                    stop_index = route_edges_list.index(edge_id)
                except ValueError:
                    continue

                # 如果停车点在当前路段或之后，添加到 XML
                if stop_index >= current_index:
                    stop_xml = (
                        f'        <stop lane="{lane_id}" endPos="{stop.startPos}" '
                        f'duration="{stop.duration}"/>\n'
                    )
                    truck_xml += stop_xml

            truck_xml += '    </vehicle>\n'
            routes_str += truck_xml

    # 结束 XML 内容
    routes_str += '</routes>'
    with open(route_filename, "w", encoding="utf-8") as f:
        f.write(routes_str)
    return route_filename